//
//  GameController.m
//  Agility
//
//  Created by Dominique d'Argent on 15.03.11.
//  Copyright 2011 Nicky Nubbel. All rights reserved.
//

#import "GameController.h"
#import "GameObjectLayer.h"
#import "SceneryObject.h"
#import "ContrailObject.h"
#import "SceneryObjectLayer.h"
#import "ContrailObjectLayer.h"


@implementation GameController

#pragma mark - Object lifecycle

//
// awakeFromNib
//
// Adds observers for |GameData|
//
- (void)awakeFromNib {    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(createLayerForGameObject:) 
                                                 name:GAME_OBJECT_NEW_NOTIFICATION
                                               object:nil];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(createLayerForSceneryObject:) 
                                                 name:GAME_SCENERY_OBJECT_NEW_NOTIFICATION
                                               object:nil];
    
    [[GameData sharedGameData] addObserver:self 
                                forKeyPath:@"state" 
                                   options:NSKeyValueObservingOptionNew
                                   context:nil];
    
    [[GameData sharedGameData] addObserver:self 
                                forKeyPath:@"score" 
                                   options:NSKeyValueObservingOptionNew
                                   context:nil];
}

//
// dealloc
//
// Releases retained objects and removes observers.
//
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:GAME_OBJECT_NEW_NOTIFICATION
                                                  object:nil];
    
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:GAME_SCENERY_OBJECT_NEW_NOTIFICATION
                                                  object:nil];
    
    [[GameData sharedGameData] removeObserver:self
                                   forKeyPath:@"state"];
    
    [[GameData sharedGameData] removeObserver:self
                                   forKeyPath:@"score"];
    
    [backgroundLayer release];
    
    [super dealloc];
}

//
// didReceiveMemoryWarning
//
// Frees some memory in case of a memory warning and hopefully saves the app
// from a crash.
//
- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
}

#pragma mark - View lifecycle

//
// viewDidLoad
//
// Sets up the backgroundLayer.
//
- (void)viewDidLoad {
    [super viewDidLoad];
    
    backgroundLayer = [self.view.layer retain];
}

//
// viewDidUnload
//
// Releases the backgroundLayer.
//
- (void)viewDidUnload {
    [super viewDidUnload];
    
    [backgroundLayer release];
    backgroundLayer = nil;
}

//
// shoulAutorotateToInterfaceOrientation:
//
// Decides whether the interface orientation should autorotate.
//
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
	return YES;
}

#pragma mark - Game Controller

//
// createLayerForGameObject:
//
// Called when a |GAME_SCENERY_OBJECT_NEW_NOTIFICATION| has been received.
// Creates a |SceneryLayer| for a newly created game object.
//
- (void)createLayerForGameObject:(NSNotification *)notification {
    NSString *gameObjectKey = [notification object];
    
    GameObjectLayer *newLayer = [[GameObjectLayer alloc] initWithGameObjectKey:gameObjectKey];
    
    [backgroundLayer addSublayer:newLayer];
    
    [newLayer release];
}

//
 // createLayerForSceneryObject:
 //
 // Called when a |GAME_OBJECT_NEW_NOTIFICATION| has been received.
 // Creates a |GameObjectLayer| for a newly created game object.
 //
- (void)createLayerForSceneryObject:(NSNotification *)notification {
    SceneryObject *sceneryObject = (SceneryObject *)[notification object];
    
    if ([sceneryObject isKindOfClass:[ContrailObject class]]) {
        SceneryObjectLayer *newLayer;
        newLayer = [[ContrailObjectLayer alloc] initWithSceneryObject:sceneryObject];
        
        [backgroundLayer addSublayer:newLayer];
        
        [newLayer start];
        [newLayer release];
    }
}

#pragma mark - View manipulation

//
// gameStateChangedToState:
//
// Reacts to game state changes. By default stops the game engine when state
// changed to |GameStateStopped|. Should be overridden to react to other state
// changes.
//
- (void)gameStateChangedToState:(GameState)newState {
    if (newState == GameStateStopped) {
        [self stop];
    }
}

//
// updateScore
//
// Should be overridden to update the view to display the new score.
//
- (void)updateScore:(CGFloat)score {
}

#pragma mark - IBActions

//
// start
//
// Starts the game.
//
- (IBAction)start {
    [[GameData sharedGameData] start];
}

//
// stop:
//
// Stops the game.
//
- (IBAction)stop {
    [[GameData sharedGameData] stop];
}

#pragma mark - Touch handling

//
// touchesBegan:withEvent:
//
// Called when touches began. Retrieves touch location and 
// forwards it to |gameData|.
//
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    
    [GameData sharedGameData].touchPoint = [touch locationInView:self.view];
}

//
// touchesMoved:withEvent:
//
// Called when touches moved. Retrieves touch location and 
// forwards it to |gameData|.
//
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    
    [GameData sharedGameData].touchPoint = [touch locationInView:self.view];
}
//
// touchesEnded:withEvent:
//
// Called when touches ended.
//
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
}

//
// touchesCancelled:withEvent:
//
// Called when touches were cancelled.
//
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
}

# pragma mark - KVO

//
// observeValueForKeyPath:ofObject:change:context:
//
// Dispatches KVO events.
//
-(void)observeValueForKeyPath:(NSString *)keyPath 
                     ofObject:(id)object 
                       change:(NSDictionary *)change
                      context:(void *)context {
    
    if ([keyPath isEqualToString:@"state"]) {
        GameState state = [[change valueForKey:NSKeyValueChangeNewKey] unsignedIntegerValue];
        
        [self gameStateChangedToState:state];
    }
    else if ([keyPath isEqualToString:@"score"]) {
        CGFloat score = [[change valueForKey:NSKeyValueChangeNewKey] floatValue];
        
        [self updateScore:score];
    }
    else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

@end
